﻿
//
//
//

namespace Microsoft.OpenTurf.Silverlight.Shared
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Runtime.Serialization.Json;
    using System.ServiceModel.Syndication;
    using System.Xml;
    using System.Xml.Linq;
    using System.Diagnostics;

    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="T">The Concrete Type of Feed that is to be downloaded</typeparam>
    public class FeedProvider<T>
    {
        public IList<IFeedItem> FeedResults
        {
            get;
            private set;
        }
        public IFeed Feed { get; private set; }

        #region ctor
        public FeedProvider()
        {
            Initialize();
        }
        public FeedProvider(IFeed feed)
        {
            Initialize();
            Feed = feed;
        }
        private void Initialize()
        {
            FeedResults = new List<IFeedItem>();
        }
        #endregion

        #region Events
        public event FeedDownloadCompleteEventHandler ProcessFeed;
        public virtual void OnFeedReady(FeedEventArgs e)
        {
            if (ProcessFeed != null)
                ProcessFeed(e);
        }
        #endregion

        public void DownloadJsonFeedAsync(Uri feedUri)
        {
            WebClient client = new WebClient();
            client.OpenReadCompleted += new OpenReadCompletedEventHandler(JsonCallBack);
            client.OpenReadAsync(feedUri);

        }
        void JsonCallBack(object sender, OpenReadCompletedEventArgs e)
        {
            DataContractJsonSerializer jsonResult = new DataContractJsonSerializer(typeof(JsonResultWrapper<T>));
            JsonResultWrapper<T> feedArray = jsonResult.ReadObject(e.Result) as JsonResultWrapper<T>;

            foreach (var item in feedArray.results)
            {
                IFeedItem feedItem = new GenericFeedItem();//(IFeedItem)IoC.Container.Resolve(typeof(IFeedItem), "IFeedItem");
                ITranslator<IFeedItem, T> provider = TranslatorProvider<T>.CurrentFeedTranslator;

                FeedResults.Add(provider.Translate(feedItem, item));
            }

            Feed.FeedItems = FeedResults;

            FeedEventArgs args = new FeedEventArgs();
            args.FeedItems = FeedResults;
            args.Feed = Feed;

            OnFeedReady(args);
        }

        [Obsolete("For Future Implementation of Generic Type XML Parsing.", true)]
        public void DownloadXmlFeedAsync(Uri feedUri)
        {
            WebClient client = new WebClient();
            client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(XmlCallBack);
            client.DownloadStringAsync(feedUri);
        }

        private void XmlCallBack(object sender, DownloadStringCompletedEventArgs e)
        {
            // Figure out Xml Serialization for KML Feed to Implement Generic Parser.
        }
    }

    public class FeedProvider
    {
        protected IList<IFeedItem> FeedResults
        {
            get;
            private set;
        }
        protected IList<IFeed> Feeds { get; private set; }
        protected IFeed Feed { get; private set; }
        protected IFeedSource FeedSource { get; private set; }
        private string _baseUrl;

        #region ctor
        public FeedProvider(string baseUrl)
        {
            Initialize();
            _baseUrl = baseUrl;
        }
        public FeedProvider(string baseUrl, IFeed feed)
        {
            Initialize();
            _baseUrl = baseUrl;
            Feed = feed;
        }
        public FeedProvider(string baseUrl, IFeedSource feedSource)
        {
            Initialize();
            _baseUrl = baseUrl;
            FeedSource = feedSource;
        }
        private void Initialize()
        {
            Feeds = new List<IFeed>();
            FeedResults = new List<IFeedItem>();
        }
        #endregion

        #region Events
        public event FeedDownloadCompleteEventHandler ProcessFeed;
        public virtual void OnFeedReady(FeedEventArgs e)
        {
            if (ProcessFeed != null)
                ProcessFeed(e);
        }
        public event FeedSourceDownloadCompleteEventHandler ProcessFeedSource;
        public virtual void OnFeedSourceReady(FeedSourceEventArgs e)
        {
            if (ProcessFeedSource != null)
                ProcessFeedSource(e);
        }
        #endregion

        public void DownloadAtomFeedAsync(Uri feedUri)
        {
            WebClient client = new WebClient();
            client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(AtomCallBack);
            client.DownloadStringAsync(feedUri);
        }
        private void AtomCallBack(object sender, DownloadStringCompletedEventArgs e)
        {
            XmlReaderSettings settings = new XmlReaderSettings();
            settings.DtdProcessing = DtdProcessing.Ignore;
            XmlReader reader = XmlReader.Create(new StringReader(e.Result), settings);

            try
            {
                SyndicationFeed atomResult = SyndicationFeed.Load(reader);

                FeedSource.ID = atomResult.Id;
                FeedSource.Title = atomResult.Title.Text;
                FeedSource.Description = atomResult.Description.Text;
                FeedSource.Link = (from l in atomResult.Links
                                   where l.RelationshipType.Equals("self")
                                   select l).FirstOrDefault().Uri;

                foreach (var item in atomResult.Items)
                {
                    IFeed feedItem = new GenericFeed();

                    feedItem.ID = item.Id;
                    feedItem.Title = item.Title.Text;
                    feedItem.Summary = item.Summary.Text;

                    foreach (SyndicationLink link in item.Links)
                    {
                        if (link.RelationshipType.Equals("enclosure"))
                        {
                            if (link.MediaType.Equals("application/vnd.google-earth.kml+xml"))
                            {
                                feedItem.Link = (link.Uri.IsAbsoluteUri) ? link.Uri : new Uri(_baseUrl + link.Uri.ToString());
                            }
                            else if (link.MediaType.Contains("image"))
                            {
                                feedItem.Icon = (link.Uri.IsAbsoluteUri) ? link.Uri : new Uri(_baseUrl + link.Uri.ToString());
                            }
                        }
                    }

                    Feeds.Add(feedItem);
                }
            }
            catch (Exception) { }

            if (FeedSource != null)
                FeedSource.Feeds = Feeds;

            FeedSourceEventArgs args = new FeedSourceEventArgs();
            args.Feeds = Feeds;
            args.FeedSource = FeedSource;

            OnFeedSourceReady(args);
        }

        public void DownloadKMLFeedAsync(Uri feedUri)
        {
            WebClient client = new WebClient();
            client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(KmlCallBack);
            client.DownloadStringAsync(feedUri);
        }
        private void KmlCallBack(object sender, DownloadStringCompletedEventArgs e)
        {
            XDocument kmlDocument = XDocument.Parse(e.Result);
            XNamespace nameSpace = kmlDocument.Root.Attributes("xmlns").First().Value;

            foreach (var item in kmlDocument.Descendants(nameSpace + "Placemark"))
            {
                IFeedItem feed = new GenericFeedItem();

                feed.Title = item.Element(nameSpace + "name").Value;

                feed.Description = item.Element(nameSpace + "description").Value;

                if (kmlDocument.Descendants(nameSpace + "Polygon").Count() > 0)
                    feed.CoordinateList = item.Element(nameSpace + "Polygon").Element(nameSpace + "outerBoundaryIs").Element(nameSpace + "LinearRing").Element(nameSpace + "coordinates").Value;
                else
                    feed.CoordinateList = item.Element(nameSpace + "Point").Element(nameSpace + "coordinates").Value;

                feed.ID = Guid.NewGuid().ToString();

                if (Feed != null)
                    feed.Icon = Feed.Icon;

                FeedResults.Add(feed);
            }

            if (Feed != null)
                Feed.FeedItems = FeedResults;

            FeedEventArgs args = new FeedEventArgs();
            args.FeedItems = FeedResults;
            args.Feed = Feed;

            OnFeedReady(args);
        }
    }
}